<?php
namespace cubox;

use cubox\provider\SQLBuild;

class Model
{
    protected App $app;
    protected Database $db;
    public string $table = '';
    public string $key = '';
    public string $comment = '';

    public int $total = 0;
    public int $pageCount = 1;

    protected SQLBuild $sqlBuild;

    public function __call(string $name, array $arguments): mixed{

        if (method_exists($this->sqlBuild,$name)){
            call_user_func_array([$this->sqlBuild,$name],$arguments);
            return $this;
        }

        throw new \Exception('Model Error:'.$name .' function does not exist');
    }

    public function __init(App $app,Database $db,array $config){
        $this->db = $db;
        $this->app = $app;
        $this->table = $config['table'];
        $this->key = $config['key']??'';
        $this->comment = $config['comment']??'';
        $this->sqlBuild = new SQLBuild();
    }

    public function getId($id)
    {
        $oldField = $this->sqlBuild->param->field;
        $this->sqlBuild->clear();
        $this->sqlBuild->param->field = $oldField;

        $this->where($this->key, $id);
        return $this->getRow();
    }

    public function getRow()
    {   
        $this->limit(0,1);
        $list = $this->getData();
        if (is_array($list) && count($list) > 0) return $list[0];
        else return  null;
    }

    public function getData():array
    {
      
        $data =  $this->db->select($this->table,$this->sqlBuild->param);
        $this->sqlBuild->clear();
        return is_array($data)?$data:[];
    }

    public function update($data)
    {
        $result = $this->db->update($this->table,$data,$this->sqlBuild->param);
        $this->sqlBuild->clear();
        return  is_array($result);
    }

    public function updateId($id, $data)
    {
        $this->sqlBuild->where($this->key, $id);
        return $this->update($data);
    }

    public function delete()
    {
        $result = $this->db->delete($this->table,$this->sqlBuild->param);
        $this->sqlBuild->clear();
        return  is_array($result);
    }

    public function deleteId($id)
    {
        $this->clear();
        $this->where($this->key, $id);
    
        return $this->delete();
    }

    public function insert($data)
    {
        $result =  $this->db->insert($this->table,$data);
        return is_array($result)? $this->getInsertId():false;
    }

    public function getInsertId():int
    {
        return $this->db->getInsertId();
    }

    public function count():int{
        return $this->mathValue('COUNT(*)');
    }


    public function max(string $field){
        return $this->mathValue('MAX('.$field.')');
    }

    public function sum(string $field){
        return $this->mathValue('SUM('.$field.')');
    }

    protected function mathValue(string $field){
        $oldField = $this->sqlBuild->param->field;
        $this->sqlBuild->param->field = [$field];
        $data = $this->db->select($this->table,$this->sqlBuild->param);
        $this->sqlBuild->param->field = $oldField;

        if (is_array($data) && is_array($data[0])){
            return (int) array_pop($data[0]);
        }else{
            return 0;
        }
    }

    public function getTable():string {
        if ($this->sqlBuild->param->alias){
            return $this->table.' AS '.$this->db->escapeName($this->sqlBuild->param->alias);
        }else{
            return $this->table;
        }
    }

    public function getKey():string{
        return $this->getField($this->key);
    }

    public function getField(string|array $filedList):string{
        

        $tableName = '';

        if ($this->sqlBuild->param->alias){
            $tableName = $this->db->escapeName($this->sqlBuild->param->alias);
        }else{
            $tableName = $this->db->escapeName($this->table);
        }


        if (is_string($filedList)){
            $filedList = [$filedList];
        }


        $list = [];

        foreach($filedList as $k=>$v){

            if (is_string($k)){
                $list[] = $tableName.'.'.$this->db->escapeName($k).' AS '.$this->db->escapeName($v);
            }else{
                
                if ($v=='*') $list[] = $tableName.'.*';
                else         $list[] = $tableName.'.'.$this->db->escapeName($v);
            }

        }

        return implode(', ',$list);
    }
   

    public function switchSort(array $ids,string $orderField = 'sort',string $order = 'asc'){
    
        $order = strtolower($order);
        $list = $this->field($orderField)->where($this->key,'in',$ids)->order($orderField,$order)->getData();
        
        $sort = [];

        foreach($list as $k=>$v){

            if ($v[$orderField]){
                $sort[] = $v[$orderField];
            }else{
                if ($order=='asc'){
                    $sort[] = $k + 1;
                }else{
                    $sort[] = count($list)- $k + 1;
                }
            }

        }


        foreach($ids as $key=>$id){
            $this->updateId($id,[$orderField =>$sort[$key]]);
        }

    }

    public function page(int $current,int $pagesize):Model{
        $this->total =  $this->count();
        $this->pageCount = ceil($this->total/$pagesize);
        
        if ($current < 1){
            $current = 1;
        }
        
        $start = ($current-1)*$pagesize;

        if ($start<0) $start = 0;
        $this->limit($start,$pagesize);

        return $this;
    }
}
